Git 常用命令速查
按功能分类整理 Git 常用命令,覆盖日常开发的配置、提交、分支、远程协作与标签操作;先以「三棵树」工作模型说明工作区、暂存区与提交的关系,随后讲清 git pull、git fetch、git merge 与 git rebase 四个命令的关系与分工,再补充三组常用操作:回滚本地与远程分支、修改已推送的提交信息、git stash 暂存中断现场,末尾处理本地 tag 与远程不一致导致同步被拒的问题。适合放在手边随查随用。
命令速查表
| 类别 | 命令 | 说明 |
|---|---|---|
| 配置 | git config --global user.name "Your Name" | 设置全局用户名 |
git config --global user.email "email@example.com" | 设置全局邮箱 | |
git config --list | 查看当前配置 | |
| 初始化 | git init | 初始化一个新的 Git 仓库 |
git clone <url> | 克隆远程仓库到本地 | |
| 查看状态 | git status | 查看工作区状态(哪些文件被修改、暂存等) |
| 添加与提交 | git add <file> | 将指定文件添加到暂存区 |
git add . | 添加当前目录所有更改到暂存区 | |
git commit -m "commit message" | 提交暂存区内容到本地仓库,并附带提交信息 | |
| 查看历史 | git log | 查看提交历史(详细) |
git log --oneline | 以单行形式显示提交历史 | |
git log --graph --all --oneline | 图形化显示所有分支的提交历史 | |
| 差异比较 | git diff | 查看工作区与暂存区之间的差异 |
git diff --staged 或 git diff --cached | 查看暂存区与最新提交之间的差异(两者等价) | |
| 撤销操作 | git checkout -- <file> | 丢弃工作区对文件的修改(恢复到最近一次暂存/提交状态) |
git reset HEAD <file> | 从暂存区移除文件(保留工作区修改) | |
git reset --hard HEAD~1 | 回退到上一个提交(会丢失最近一次提交的所有更改),慎用 | |
git revert <commit> | 生成一笔反向提交,撤销指定提交的改动(不改写历史) | |
| 分支管理 | git branch | 列出本地所有分支 |
git branch <branch-name> | 创建新分支 | |
git checkout <branch-name> | 切换到指定分支 | |
git switch <branch-name> | (Git 2.23+)切换分支(推荐替代 checkout) | |
git checkout -b <branch-name> | 创建并切换新分支 | |
git branch -d <branch-name> | 删除已合并的分支 | |
git branch -D <branch-name> | 强制删除分支(即使未合并) | |
git merge <branch-name> | 合并指定分支到当前分支 | |
| 远程操作 | git remote -v | 查看远程仓库地址 |
git remote add origin <url> | 添加远程仓库(通常命名为 origin) | |
git push -u origin <branch> | 首次推送本地分支到远程,并设置上游跟踪 | |
git push | 推送当前分支到关联的远程分支 | |
git pull | 拉取远程更新并合并(默认相当于 fetch + merge) | |
git fetch | 获取远程更新但不合并 | |
| 标签管理 | git tag | 列出所有标签 |
git tag <tagname> | 创建轻量标签 | |
git tag -a <tagname> -m "message" | 创建带注释的标签 | |
git push origin <tagname> | 推送指定标签到远程 | |
git push origin --tags | 推送所有标签到远程 | |
| 其他实用命令 | git stash | 临时保存当前工作区和暂存区的修改 |
git stash pop | 恢复最近一次 stash 的内容 | |
git reflog | 查看 HEAD 变更记录(可用于找回「丢失」的提交) | |
git show <commit-id> | 显示某次提交的详细信息 |
工作模型:三棵树
本地仓库由 Git 维护的三棵树组成:工作目录(工作区)、暂存区(Index/stage,保存待提交的临时改动)、HEAD(指向最近一次提交的结果)。
日常操作就是在这几棵树之间搬动改动:git status 查看文件状态(已修改未暂存、已暂存未提交),git add 把工作区改动放进暂存区,git commit 把暂存区内容提交到 HEAD 并清空暂存区,git push 把本地提交送到远端。理解这个模型后,后面 pull/fetch/merge 的行为与 git diff 各变体的含义都有了落点:
git diff # 工作区 vs 暂存区
git diff --cached # 暂存区 vs HEAD(add 之后仍能看)
git diff <source_branch> <target_branch> # 两个分支之间 git add 之后 git diff 无输出并不是差异丢失——默认的 diff 只比较工作区与暂存区,add 后两者一致自然没有输出,要看已暂存的改动用 git diff --cached(与 --staged 等价)。
pull、fetch、merge 与 rebase 的关系
git fetch 与 git pull 都用于更新本地代码,区别在于是否合并:
git fetch只获取远端仓库的分支数据,更新本地的远程跟踪分支(如origin/master),不进行合并,工作区不受影响git pull在 fetch 的基础上更进一步。官方文档的描述:把远端仓库的变更合入当前分支——当前分支落后于远端时,默认 fast-forward(快进)到远端;两者发生分歧时,需要通过--rebase或--no-rebase(或pull.rebase配置)指定调和方式
更准确地说,git pull 先执行 git fetch,然后根据配置或命令行参数调用 git merge 或 git rebase 完成分支调和,默认是 merge。
merge 与 rebase 处理分歧的结果不同。假设当前分支与远端出现如下分歧:
A---B---C master on origin
/
D---E---F---G feature
^ origin/master in your repository git pull(merge 方式)会把远端新提交(A、B、C)合并到当前分支,创建一个新的合并提交 H:
A---B---C origin/master
/ \
D---E---F---G---H feature rebase 则把当前分支上不在上游(<upstream>)中的提交(F、G)暂存到临时区域,将分支重置到上游最新提交,再把这些提交逐个重放到顶部。上游提交 C 不会被改写,被改写的是自己的 F、G(变成 F'、G'):
A---B---C---F'--G' feature
/
D---E
^ origin/master in your repository merge 保留真实的分叉历史,rebase 产出线性的历史记录。整理已有提交历史的更多操作(交互式 rebase、cherry-pick)见 Git Rebase 与 Cherry-pick 实用指南。
修改已推送的 commit 信息
场景:最近一次 commit 已经推送到远端,发现提交信息写错了,想改过来。前提是本地处于该分支最新状态。
git commit --amend进入编辑器(默认 vim):按i进入编辑模式修改提交信息,编辑完按Esc,输入:wq保存退出git push -f强制推送,覆盖远端
编辑器不一定是 vim,能保存即可,例如 nano:Ctrl+O 保存,Ctrl+X 退出。
force push 会改写远端历史:该 commit 已被他人拉取时,会给他们制造冲突,共享分支上慎用。更稳妥的写法是 git push --force-with-lease——远端在本地不知情时被更新过,推送会被拒绝,降低覆盖他人提交的风险。
回滚:本地与远程分支
本地回滚用 git reset:
git reset --hard <commit-id> # 回滚到 commit-id,其后的提交全部去除
git reset --hard HEAD~3 # 回滚最近 3 次提交 远程回滚的典型场景:自动部署系统发布后发现问题,需要把分支退回某个 commit 再重新发布。原理是先把本地分支退回去,再让远程分支重新指向旧提交,操作前务必备份。两种方法效果等价,方法二更直接:
# 方法一:删远程分支重建
git checkout your_branch
git pull
git branch your_branch_backup # 备份当前分支
git reset --hard <the_commit_id> # 回退到指定的 commit_id
git push origin :your_branch # 删除远程分支(等价写法 --delete)
git push origin your_branch # 用回滚后的本地分支重建远程分支
git push origin :your_branch_backup # 确认成功后删除备份分支
# 方法二:强制推送
git checkout your_branch
git pull
git branch your_branch_backup
git reset --hard <the_commit_id>
git push -f origin your_branch # 强制覆盖远程分支 git push -f 会绕过远端保护,若服务端开启了分支保护,需要先解除保护或改用 git revert 生成反向提交。分支已被他人拉取时,优先用 git revert,避免强推改写公共历史。
git stash:暂存中断现场
开发中途要切去处理别的问题,手头改动不适合带着半成品提交时,用 git stash 把当前工作区和暂存区的修改整体存起来,稍后恢复。
git stash 默认忽略未跟踪和被 ignore 的文件;stash 记录只存在本地,不会随 git push 上传。
git stash push -m "message" # 暂存并附说明(推荐)
git stash list # 查看暂存栈
git stash save "message"是旧写法,Git 2.16 起已弃用;push还支持指定路径,只暂存部分文件。
处理未跟踪与被忽略的文件:
git stash -u/git stash --include-untracked:连未跟踪文件一起暂存git stash -a/git stash --all:连被 ignore 的文件也一起暂存
恢复与清理:
git stash apply stash@{x} # 释放编号 x 的暂存,记录保留在 list 中
git stash pop # 释放最近一次暂存,并从 list 中删除该记录
git stash drop stash@{1} # 删除指定暂存
git stash clear # 清空暂存栈 apply 与 pop 的区别只在是否出栈:需要把同一次暂存恢复到多个分支时用 apply。
本地 tag 与远程不一致导致同步被拒
场景:git pull / git fetch 时报错,同步中断:
! [rejected] v3.38.0 -> v3.38.0 (would clobber existing tag) 本地存在与远程同名的 tag,但两者指向不同的提交。常见原因是本地重新打过这个 tag(如 git tag -f),或者远程 tag 被人删掉重建过。Git 出于安全考虑拒绝覆盖本地 tag。
处理思路是删掉不一致的本地 tag,再从远程重新拉取:
- 查看远程 tag:
git ls-remote -t <remote> - 查看本地 tag:
git tag -l - 删除与远程不一致的本地 tag:
git tag -d v3.38.0 - 重新拉取远程 tag 并同步代码:
git fetch origin
git pull 关于 --prune-tags:git fetch origin --prune-tags 会按 refs/tags/*:refs/tags/* 强制拉取远程全部 tag,但单独使用时并不会清理本地多余的 tag——官方文档写明,清理仅在 --prune 同时启用时生效。要一步清掉本地已不在远程的 tag,用:
git fetch origin --prune --prune-tags 也可以写进配置长期生效:
git config fetch.prune true
git config fetch.pruneTags true 要点
- 查任意命令的权威说明用
git help <command> --hard与 force push 都是破坏性操作,执行前确认自己清楚后果- Git 2.23 起分支操作推荐用
git switch、撤销暂存推荐用git restore --staged,职责比git checkout清晰